1:状态管理和使用场景(vuex):
vuex所解决的问题与bus类似,它作为Vue的一个插件使用,可以更好的管理和维护整个项目的组件状态。
在实际的业务逻辑中,经常有跨组件共享数据的需要,因此Vuex的设计就是用来更好的管理统一管理组件状
态的。它定义了一系列规范来使用和操作数据,使组件应用更加高效。
1.1: Vuex的基本使用?
1.1.1: 首先通过NPM进行安装:
npm install --save vuex
1.1.2: 在main.jsl文件里,通过Vuer.use()使用Vuex
import Vuex from 'vuex'
import createrLogger from 'vuex/dist/logger'
const debug = process.env.NODE_ENV !== 'production'
Vue.use(Vuex)
1.1.3: 进行路由配置
const store = new Vuex.Store({
// vuex的配置
state: {
count: 0,
list: [1, 5, 8, 10, 30, 50]
},
mutations: {
increment (state) {
state.count++;
},
decrease (state, n = 1) { // n= n || 1
state.count -= n;
},
ceshiTypeFunc (state, params) {
state.count += params.count;
}
},
actions: {
increase (context) {
context.commit('increase');
},
asyncIncreasement(xontext) {
return new Promise((resolve, reject) => {
this.$nextTick(() => {
contect.commit('increase');
resolve();
})
})
}
}
getters: {
filterList: state => {
return state.list.filter(item => item< 10);
},
listCount: (state, getters, rootState) => {
// rootState.count 来访问根节点的状态。
return getters.filterList .length;
}
},
plungins: debug ? [crateLogger()] : [];
});
仓库store包含了应用的数据(状态)和操作过程。Vuex里面的数据都是响应式的,在任何组件使用同一store的数据
时候,只要store的数据变化的时候,对应的组件也会立即更新。
在任何组件中,可以直接通过$store.state.count读取。(模板),直接写在template中会显得会很乱, 可以使用一个
计算属性来进行显示:
export default {
computed: {
count() {
return this.$store.state.count;
},
list() {
return this.$store.state.list.filter(item => item < 10);
},
listTwo() {
return this.$store.getters.filterList;
},
listCount() {
return this.$store.getters.listCount;
}
}
}
1.1.4: 状态值更改?
在组件中,来自store的数据只能进行读取,不能手动更改, 改变store中的数据的时候唯一途径是使用显示的提交 mutations(mutations是Vuex的第二个选项, 用来直接修改state里的数据).
在组件中使用this.$store.commit方法来进行执行mutations中的方法的(例如点击事件)
methods: {
handIncrease () {
this.$store.commit('increase');
},
handDecrease () {
this.$store.commit('decrease');
},
handCeshiFunc () {
this.$store.commit({
type: 'ceshiTypeFunc ',
count: 10
});
},
handActionIncrease() {
this.$store.dispatch('increase');
},
handAsyncIncreasement() {
this.$store.dispatch('asyncIncreasement ').then(() => {
console.log(this.$store.state.count);
})
}
}
这样看起来就像Javascript的观察者模式,组件只负责提交一个事件名, Vuex对应的mutations来完成业务逻辑。
mutation还可以接受第二个参数, 可以是数字、字符串或者对象等。
注意,mutation里尽量不要使用异步操作数据, 如果异步操作数据,组件在commit后,数据不会立即更新,而且不知 道什么时候改变。
1.1.5: 高级用法?
Vuex还有其他3个选项可以使用: getters、actions、modules.
getters:
如果只是想得到小于10的数据, 最容易想到的是通过计算属性进行过滤,这样写是没有问题的,但是如果是
其他组件也要使用过滤后的数据的时候,就得吧computed的代码完全复制一份了,而且当需要修改过滤方法 的时候,每个用到的组件都需要进行修改,这明显不好, 所可以使用getters.
注意: getters也可以依赖其他的getters,把getters作为第二个参数。
actions:
actions与mutation很像,不同的是action里面提交的是mutations,并且可以异步操作业务逻辑。
action在组建内通过$store.dispatch触发。
modules:
module将store分割到不同的模块,当你的项目足够大的时候,store里的state、getters、mutations、 actions会分厂多,放再main.js里面显得不是很友好,使用modules可以将它们写到不同的文件里面,每个 modules都拥有自己的state、getters、mutations、actions,而且可以多层嵌套。
const modulesA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const modulesB = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const store = new Vuex.Store({
modules: {
a: modulesA,
b: modulesB
}
})
1.1.6: 比较?
mutations、actions看起来很相似,可能会觉得不知道哪个, 但是Vuex很像是一种与开发者的约定,所以涉及
改变数据的,就使用mutations,存在业务逻辑的就用actions.至于将业务逻辑放在你action里还是Vue组件里完 成的根据实际的业务逻辑拿捏。
1.2: 辅助函数?
Vuex除了提供我们Store对象之外,还对外提供了一系列的辅助函数,方便我们在代码中使用Vuex,提供了操作store
的各种属性的一系列的语法糖。
1.2.1: mapState
mapState工具函数会将store中的state映射到局部计算中,为了更好的理解它的实现。
前:(对象)
import { mapState } from 'vuex'
export default {
computed: mapState({
count: state => state.count,
// 传入字符串‘count’ 等同于`state => state.count`
countAlia: 'count',
// 想要访问局部状态,就必须借助于一个普通函数,函数中使用`this`获取局部状态。
countPlusLocalState (state) {
return state.count + this.localCount;
}
})
}
经过mapStore函数调用之后的结果:
import {mapState} from 'vuex'
export default {
computed: {
count() {
return this.$store.state.count;
},
countAlia () {
return this.$store.state['count'];
},
countPlusLocalState () {
return this.$store.state.count + this.localCount
}
}
前:(数组)
import { mapState } from 'vuex'
export default {
computed: mapState([
'count'
])
}
经过mapStore函数调用之后的结果:
import {mapState} from 'vuex'
export default {
computed: {
count() {
return this.$store.state['count'];
}
}
当计算属性名称和状态子树名称对应相等的时候,我们可以向,mapState工具函数中传入一个字符串数组。
computed: mapState({
// 映射this.count 到 this.$store.state.count
'count'
});
通过例子可以明显看出来mapState函数可以接受一个对象,也可以接受一个数组。
1.2.2: mapGetters
mapGetters工具函数将store中的getters映射到局部计算属性属性中,它的功能和mapsState非常类似
前(数组)
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters([
'doneTodoCount',
'anotherGetter',
// ...
])
}
}
经过mapGetters 函数调用之后的结果:
import { mapGetters } from 'vuex'
export default {
computed:{
doneTodoCount () {
return this.$store.getters['doneTodoCount '];
},
anotherGetter() {
this.$store.getters['anotherGetter '];
}
}
}
前(对象)
computed: mapGetters({
doneCount: 'doneTodosCount'
})
经过mapGetters 函数调用之后的结果:
computed: {
doneCount() {
return this.$store.getters['doneTodosCount ']
}
}
1.2.3: mapActions
mapActions工具函数将store中的dispatch方法映射到组件的methods中,和mapState、mapGetters类似,只不过
它映射的是地方不是计算属性,而是组件的methods对象上面:
前
import {mapActions} from 'vuex'
export default {
methods: {
...mapActions([
'increase' // 映射this.increase() 到 this.$store.dispatch('increase');
]),
...mapActtions([
add: 'increase' // 映射 this.add() 到 this.$store.dispatch('increase');
])
}
}
经过mapActions 函数调用之后的结果:
import { mapActions } from 'vuex'
export default {
methods:{
increase(...arg) {
return this.$store.dispatch.apply(this.$store, ['increase'].concat(args))
},
add(...arg) {
return this.$store.dispatch.apply(this.$store, ['increase'].concat(args));
}
}
}
1.2.4: mapMutations:
mapMutations 工具函数会将store中的commit方法映射到组件的methods中,和mapActions的功能几乎一样
前
import { mapMutatiosn } from 'vuex'
export default {
methods: {
...mapMutatiosn ([
'increase' // 映射this.increase() 到 this.$store.commit('increase');
]),
...mapMutatiosn ([
add: 'increase' // 映射 this.add() 到 this.$store.commit('increase');
])
}
}
经过mapMutatiosn 函数调用之后的结果:
import { mapMutatiosn } from 'vuex'
export default {
methods:{
increase(...arg) {
return this.$store.commit.apply(this.$store, ['increase'].concat(args))
},
add(...arg) {
return this.$store.commit.apply(this.$store, ['increase'].concat(args));
}
}
}
1.3: 插件
Vuex的store接受一个plung 选项,一个Vuex的插件就是一个简单的方法,接受store作为唯一的参数。
插件的作用通常阿是用来监听每次mustations的变化的,来做一些事情。
在store的构造函数的最后,我们通过如下代码调用插件。
import devtoolPlungin from './plungins/devtool'
plungins.concat(devtoolPlungin).forEach(plungin => plungin(this))
2: 中央事件总线的使用(vue-bus)
在本地目录下创建目录vue-bus,在目录vue-bus下插件vue-bus.js文件,此时就给Vue添加了一个属性$bus,并且代理了$emit, $on,$off三个方法, 代理如下
// vue-bus.js
const install = function(Vue) {
const Bus = new Vue({
methods: {
emit(event, ...args) {
this.$emit(event, ...args);
},
on(event, ...args) {
this.$on(event, ...arg);
},
off(event, callback) {
this.$off(event, callback);
}
}
});
Vue.prototype.$bus = Bus;
}
export default install;
使用:
// 在main.js 文件中使用
import VueBus from './vue-bus';
Vue,use(VueBus);
// 在view中仙剑一个组件Counter.vue
接收前
<template>
<div>
{{number}}
</div>
<button @click="handAddRandom">随机增加<button>
</template>
<script>
export default {
props: {
number: {
type:Number
}
},
methods: {
handleAddRandom() {
// 随机回去0-100之间的数值
const num = Math.floor(Match.random() * 100 + 1);
this.$bus.emit('add', num);
}
}
}
</script>
接收后
<template>
<div>
<Counter :number="number"></Counter>
</div>
·</template>
import Counter from './conter.vue'
<script>
export default {
componrents: {
Counter
},
data: {
return : {
number: 0
}
},
methods: {
handlerAddRandom(num) {
this.number = num;
}
}
created() {
this.$bus.on('add', this.handlerAddRandom )
},
beforeDestory() {
this.$bus.off('add', this.handlerAddRandom)
}
}
</script>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。